package com.ccys.common.util;


import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import com.ccys.common.constants.ContextConstants;
import com.ccys.common.enums.CodeEnum;
import com.ccys.common.exception.ParamException;
import com.ccys.common.util.easyExcel.EasyExcelUtil;
import com.ccys.common.util.easyExcel.NewsExcelDTO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;


/**
 * Kit 工具类
 */
@Slf4j
@Component
@SuppressWarnings("unchecked")
public class Kit {

    public static final SimpleDateFormat SDF_UTC = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    // 可以生成随机字符串的字符集合，包含大写字母和数字
    private static final String CHAR_UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final String DIGITS = "0123456789";
    private static final String ALPHA_NUMERIC = CHAR_UPPER + DIGITS;
    private static final Random random = new SecureRandom();


    static {
        SDF_UTC.setTimeZone(TimeZone.getTimeZone("UTC"));
    }

    /**
     * 将字符串date解析为Date对象的方法
     *
     * @param dateString 时间字符串
     * @param format 时间格式字符串
     * @return
     */
    public static Date parseDate(String dateString, String format) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(format);
            return sdf.parse(dateString);
        } catch (ParseException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 计算两个时间相差的天数
     *
     * @param endDate   结束时间
     * @param startDate 开始时间
     * @return
     */
    public static long calculateDateDifferenceInDays(Date endDate, Date startDate) {
        long differenceInMillies = endDate.getTime() - startDate.getTime();
        return differenceInMillies / (24 * 60 * 60 * 1000);
    }

    /**
     * @param date   传入date
     * @param format 时间格式
     * @return 格式化之后的时间字符串
     */
    public static String formatDate(Date date, String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(date);
    }

    /**
     * 生成一个随机的14位数字字符串。
     *
     * @return 随机生成的14位数字字符串
     */
    public static String getCodeStr() {
        // 创建一个StringBuilder对象用于构建最终的字符串
        StringBuilder randomNumberString = new StringBuilder();

        // 创建一个Random对象用于生成随机数
        Random random = new Random();

        // 循环14次，每次生成一个0到9之间的随机数字，并将其添加到字符串构建器中
        for (int i = 0; i < 14; i++) {
            int digit = random.nextInt(10); // 生成一个0到9的随机整数
            randomNumberString.append(digit); // 将生成的数字追加到字符串构建器中
        }

        // 将构建好的字符串构建器转换为字符串并返回
        return randomNumberString.toString();
    }


    /**
     * 检查是否为整数
     *
     * @param str 传入的字符串
     * @return
     */
    public static boolean isInteger(String str) {
        try {
            Integer.parseInt(str);
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    /**
     * 计算当前时间过去了多少天
     *
     * @param pastDate 过去的时间
     * @return
     */
    public static long calculateDaysSinceDate(Date pastDate) {
        // 获取当前日期
        LocalDate currentDate = LocalDate.now();

        // 将java.util.Date转换为LocalDate
        LocalDate convertedPastDate = pastDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();

        // 使用ChronoUnit的between方法计算两个日期之间的天数差
        long daysBetween = ChronoUnit.DAYS.between(convertedPastDate, currentDate);

        return daysBetween;
    }


    /**
     * 传入一个时间字符串以及时间格式字符串 - 返回转换之后的date对象
     *
     * @param dateStr    日期字符串
     * @param dateFormat 日期格式
     * @return 转换后的Date对象，如果转换失败返回null
     */
    public static Date convertToDate(String dateStr, String dateFormat) {
        // 设置日期格式化对象，指定日期格式为yyyy/MM/dd
        SimpleDateFormat format = new SimpleDateFormat(dateFormat);
        try {
            // 将日期字符串解析为Date对象
            Date date = format.parse(dateStr);
            return date;
        } catch (ParseException e) {
            // 解析失败，打印异常信息并返回null
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 将Base64编码的图片字符串转换为InputStream
     *
     * @param base64ImageString Base64编码的图片字符串
     * @return 图片内容的InputStream
     */
    public static InputStream convertBase64ImageToInputStream(String base64ImageString) {
        // 移除Base64字符串中的数据头信息，如"data:image/png;base64,"
        String base64Image;
        if (base64ImageString.contains(",")) {
            base64Image = base64ImageString.split(",")[1];
        } else {
            base64Image = base64ImageString;
        }

        // 解码Base64字符串
        byte[] imageBytes = Base64.decodeBase64(base64Image);

        // 将字节数组转换为InputStream
        InputStream inputStream = new ByteArrayInputStream(imageBytes);

        return inputStream;
    }


    /**
     * 根据传入的出生日期字符串计算年龄 - 时间字符串和格式需要相对于，否则抛出异常
     *
     * @param birthDateString 出生日期字符串
     * @param dateFormat      格式,比如：yyyy/MM/dd
     * @return 年龄
     * @throws ParseException 如果传入的日期格式不正确，将抛出异常
     */
    public static Integer calculateAge(String birthDateString, String dateFormat) {
        try {
            // 定义日期格式
            SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
            // 将字符串转换为Date类型
            Date birthDate = sdf.parse(birthDateString);

            // 获取当前日期
            Calendar currentDate = Calendar.getInstance();
            // 获取出生日期
            Calendar birthDateCalendar = Calendar.getInstance();
            birthDateCalendar.setTime(birthDate);

            // 计算年龄
            int age = currentDate.get(Calendar.YEAR) - birthDateCalendar.get(Calendar.YEAR);
            // 如果当前日期还没到出生日期的月份或者日子，则年龄减一
            if (currentDate.get(Calendar.MONTH) < birthDateCalendar.get(Calendar.MONTH) ||
                    (currentDate.get(Calendar.MONTH) == birthDateCalendar.get(Calendar.MONTH) &&
                            currentDate.get(Calendar.DAY_OF_MONTH) < birthDateCalendar.get(Calendar.DAY_OF_MONTH))) {
                age--;
            }

            return age;
        } catch (Exception e) {
            log.error("获取年龄失败，请检查传入的参数格式！");
        }
        return null;
    }


    /**
     * 根据时区获取当前星期几
     *
     * @param timeZone 时区值
     * @return 注意这里返回的数字值为：0-星期一，1-星期二，3-星期四，4-星期五，5-星期六，6-星期日
     */
    public static int getWhatDayIsToday(Integer timeZone) {
        // 构建时区对象
        String timeZoneID = "GMT" + (timeZone >= 0 ? "+" : "") + timeZone;
        TimeZone customTimeZone = TimeZone.getTimeZone(timeZoneID);

        // 设置时区
        Calendar calendar = Calendar.getInstance(customTimeZone);

        // 获取当前星期几的数字值，其中1代表星期日，2代表星期一，以此类推，7代表星期六
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);

        // 将数字值转换为0到6的范围，0代表星期一，1代表星期二，以此类推，6代表星期日
        return (dayOfWeek + 5) % 7;
    }


    /**
     * 获取给定日期至今的所有年月 - 返回的list值示例："2023-10","2023-11"....升序，日期最小的在前面
     *
     * @param date 给定的日期
     * @return 包含所有年月的列表
     */
    public static List<String> getMonthsTillNow(Date date) {
        List<String> list = new ArrayList<>();
        DateFormat format = new SimpleDateFormat("yyyy-MM"); //定义日期格式

        Calendar start = Calendar.getInstance();
        start.setTime(date); //设置开始日期

        Calendar end = Calendar.getInstance(); //设置结束日期为当前日期
        end.set(Calendar.DAY_OF_MONTH, end.getActualMaximum(Calendar.DAY_OF_MONTH)); //将结束日期设置为该月的最后一天

        //当开始日期小于或等于结束日期时循环
        while (!start.after(end)) {
            //添加到列表
            list.add(format.format(start.getTime()));
            //开始日期加1个月
            start.add(Calendar.MONTH, 1);
        }
        return list;
    }


    /**
     * 根据传入的date时间获取到现在一共过去多少月
     *
     * @param startDate 开始时间
     * @return 月数
     */
    public static Integer getNumberOfMonths(Date startDate) {
        // 将Date对象转换为LocalDate对象
        LocalDate localDate = startDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        // 获取当前日期
        LocalDate now = LocalDate.now();
        // 计算日期之间的区间
        Period period = Period.between(localDate, now);
        // 返回区间的月份数
        int months = period.getMonths();
        if (months < 1) {
            months = 1;
        }
        return months;
    }


    /**
     * @param utcDate        当前utc时间
     * @param timeZoneOffset 时区值
     * @return 根据时区值转换之后的 时分字符串 例如：传入2024-01-17 08:00:00 时区值为8 返回的字符串为 16:00
     */
    public static String getTimeStrByTimeZone(Date utcDate, int timeZoneOffset, String format) {
        // 创建一个新的Calendar实例，并将其设置为传入的utcDate
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(utcDate);

        // 根据时区偏移量调整时间
        calendar.add(Calendar.HOUR_OF_DAY, timeZoneOffset);

        // 创建SimpleDateFormat对象，设置期望的输出格式
        SimpleDateFormat targetFormat = new SimpleDateFormat(format);
        // 格式化Calendar对象为指定时区的时间字符串
        String formattedDate = targetFormat.format(calendar.getTime());
        return formattedDate;
    }

    public static Date getTimeByTimeZone(Date utcDate, int timeZoneOffset) {
        // 创建一个新的Calendar实例，并将其设置为传入的utcDate
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(utcDate);

        // 根据时区偏移量调整时间
        calendar.add(Calendar.HOUR_OF_DAY, timeZoneOffset);

        return calendar.getTime();
    }


    /**
     * 将UTC日期和时区值转换为特定格式的字符串
     * 这个方法返回的时间格式为：Jan 05 2024 16:18:00 (GMT+8)
     * 会将月份设置为缩写英文
     *
     * @param utcDate        UTC日期
     * @param timeZoneOffset 时区值
     * @return 格式化的日期字符串
     */
    public static String formatUtcDate(Date utcDate, int timeZoneOffset) {
        try {
            // 创建一个新的Calendar实例，并将其设置为传入的utcDate
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(utcDate);

            // 根据时区偏移量调整时间
            calendar.add(Calendar.HOUR_OF_DAY, timeZoneOffset);

            // 创建SimpleDateFormat对象，设置期望的输出格式
            SimpleDateFormat targetFormat = new SimpleDateFormat("MMM dd yyyy HH:mm:ss", Locale.ENGLISH);

            // 格式化Calendar对象为指定时区的时间字符串
            String formattedDate = targetFormat.format(calendar.getTime());

            // 构造时区字符串
            String timeZonePart = String.format(" (GMT%+d)", timeZoneOffset);
            formattedDate += timeZonePart;

            return formattedDate;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 根据传入的utc时间对象以及时区以及时间格式获得转换之后的时间字符串
     *
     * @param utcDate    utc时间对象
     * @param timeZone   时区值
     * @param timeFormat 指定时间格式 - 可为null - 为null时使用默认yyyy-MM-dd年月日格式
     * @return
     */
    public static String getDateByTimeZone(Date utcDate, Integer timeZone, String timeFormat) {
        //时间格式
        String format = "yyyy-MM-dd";
        //判断是否传入指定时间格式
        if (ObjectUtil.isNotEmpty(timeFormat)) {
            //如果传入则设置
            format = timeFormat;
        }
        // 最终需要得到的日期格式
        SimpleDateFormat localDateFormat = new SimpleDateFormat(format);
        // 根据偏移量创建新的时区
        TimeZone localTimeZone = TimeZone.getTimeZone(String.format("GMT%+d", timeZone));
        // 根据偏移量调整时间
        Date localDate = DateUtil.offsetHour(utcDate, timeZone);
        // 设置新时区的格式化器
        localDateFormat.setTimeZone(localTimeZone);
        // 格式化到最终时间字符串并返回
        return localDateFormat.format(localDate);
    }

    /**
     * 判断一个日期是否在两个日期之间
     *
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @param checkDate 待判断的日期
     * @return 如果checkDate在startDate和endDate之间，返回true，否则返回false
     * @throws ParseException 如果日期转换出错
     */
    public static boolean isDateBetween(Date startDate, Date endDate, Date checkDate) {
        // checkDate时间在startDate之后或者相等，并且在endDate之前或者相等，则表示在区间内
        return !checkDate.before(startDate) && !checkDate.after(endDate);
    }

    /**
     * 在当前时间基础上增加指定的天数
     *
     * @param days 要增加的天数
     * @return 增加天数后的日期对象
     */
    public static Date addDays(int days) {
        // 获取当前时间的Calendar实例
        Calendar calendar = Calendar.getInstance();
        // 在当前时间基础上增加天数
        calendar.add(Calendar.DAY_OF_MONTH, days);
        // 从Calendar实例中获取增加天数后的Date对象
        return calendar.getTime();
    }

    /**
     * 传入字符串 - 并且传入要获取的后几位
     * 比如字符串为 123456789 length为6 返回的字符串为：456789
     *
     * @param str    字符串
     * @param length 截取后几位？
     * @return
     */
    public static String truncateStringByLength(String str, Integer length) {
        // 如果字符串长度小于length，直接返回原字符串
        if (str.length() <= length) {
            return str;
        }
        // 截取字符串后length位
        return str.substring(str.length() - length);
    }


    /**
     * 生成指定长度的随机字符串，包含大写字母和数字。
     *
     * @param length 指定的字符串长度
     * @return 生成的随机字符串
     */
    public static String getStrByLength(int length) {
        if (length <= 0) {
            throw new IllegalArgumentException("字符串长度必须为正数");
        }

        StringBuilder sb = new StringBuilder(length);
        for (int i = 0; i < length; i++) {
            sb.append(ALPHA_NUMERIC.charAt(random.nextInt(ALPHA_NUMERIC.length())));
        }
        return sb.toString();
    }

    /**
     * 获取 UTC 时间
     */
    public static Date getUtcDate() throws ParseException {
        return SDF.parse(getUtcDateStr());
    }

    /**
     * 获取 UTC 时间字符串
     */
    public static String getUtcDateStr() {
        return SDF_UTC.format(new Date());
    }

    // 得到随机数串
    public static String getRandomNumber(int length) {
        Double r = Math.random() * Math.pow(10, length);
        String ra = String.valueOf(r.longValue());
        String radom = ra;
        if (ra.length() < length) {
            for (int i = 0; i < length - ra.length(); i++) {
                radom = "0" + radom;
            }
        }
        return radom;
    }


    /**
     * 根据生日获取年龄
     *
     * @param birthDate 生日
     * @return
     */
    public static Integer getAge(Date birthDate) {
        if (birthDate == null) {
            throw new IllegalArgumentException("The birthDate should not be null");
        }

        // 将 Date 类型转换为 LocalDate 类型
        LocalDate birthLocalDate = birthDate.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate();

        // 获取当前日期
        LocalDate currentDate = LocalDate.now();

        // 计算两个日期之间的 Period
        Period period = Period.between(birthLocalDate, currentDate);

        // 返回计算出的年份
        return period.getYears();
    }

    /**
     * 生成6位短信验证码
     *
     * @return
     */
    public static String getMsgCode(int length) {
        Random random = new Random();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < length; i++) {
            int digit = random.nextInt(10);
            sb.append(digit);
        }
        return sb.toString();
    }

    /**
     * 从网络Url中下载文件
     */
    public static void downLoadFromUrl(String urlStr, String fileName, String savePath) throws IOException {
        URL url = new URL(urlStr);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        //设置超时间为3秒
        conn.setConnectTimeout(3 * 1000);
        //防止屏蔽程序抓取而返回403错误
        conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");

        //得到输入流
        InputStream inputStream = conn.getInputStream();
        //获取自己数组
        byte[] getData = readInputStream(inputStream);

        //文件保存位置
        File saveDir = new File(savePath);
        if (!saveDir.exists()) {
            saveDir.mkdir();
        }
        File file = new File(saveDir + File.separator + fileName);
        FileOutputStream fos = new FileOutputStream(file);
        fos.write(getData);
        if (fos != null) {
            fos.close();
        }
        if (inputStream != null) {
            inputStream.close();
        }


        System.out.println("info:" + url + " download success");

    }


    /**
     * 从输入流中获取字节数组
     *
     * @param inputStream
     * @return
     * @throws IOException
     */
    public static byte[] readInputStream(InputStream inputStream) throws IOException {
        byte[] buffer = new byte[1024];
        int len = 0;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        while ((len = inputStream.read(buffer)) != -1) {
            bos.write(buffer, 0, len);
        }
        bos.close();
        return bos.toByteArray();
    }


    /**
     * 目标日期加  整数天后的  日期
     */
    public static Date plusDay(int num, Date newDate) {
        Calendar ca = Calendar.getInstance();
        ca.setTime(newDate);
        ca.add(Calendar.DATE, num);// num为增加的天数，可以改变的
        newDate = ca.getTime();
        return newDate;
    }

    public static Date plusHour(int num, Date newDate) {
        Calendar ca = Calendar.getInstance();
        ca.setTime(newDate);
        ca.add(Calendar.HOUR, num);// num为增加的天数，可以改变的
        newDate = ca.getTime();
        return newDate;
    }

    public static Date plusMinute(int num, Date newDate) {
        Calendar ca = Calendar.getInstance();
        ca.setTime(newDate);
        ca.add(Calendar.MINUTE, num);// num为增加的分钟，可以改变的
        newDate = ca.getTime();
        return newDate;
    }

    public static Date plusSecond(int num, Date newDate) {
        Calendar ca = Calendar.getInstance();
        ca.setTime(newDate);
        ca.add(Calendar.SECOND, num);// num为增加的秒，可以改变的
        newDate = ca.getTime();
        return newDate;
    }


    /**
     * 目标日期减去天数  后的日期
     */
    public static Date subtractDay(int num, Date newDate) throws Exception {
        Calendar ca = Calendar.getInstance();
        ca.setTime(newDate);
        ca.set(Calendar.DAY_OF_YEAR, ca.get(Calendar.DAY_OF_YEAR) - num);
        newDate = ca.getTime();
        return newDate;
    }

    public static HttpServletRequest getRequest() {
        return RequestContextHolder.getRequestAttributes() != null ? ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest() : null;
    }


    /**
     * 获取加密密码
     *
     * @param password
     * @return
     */
    public static String getPassword(String password) {
        return Kit.getMD5Str(ContextConstants.PROJECT_NAME + password);
    }

    /**
     * 表单参数校验 代替统一校验@NotNull 递归校验
     * 事务回滚在外部方法处理
     * 这里抛出ParamException丢给全局处理，代替返回结果
     *
     * @param data
     * @param params 需要校验的参数
     * @return
     */
    public static <T> void allParamValid(T data, String... params) {
        for (int i = 0; i < params.length; i++) {
            String param = params[i];
            if (!paramValid(data.getClass(), data, param)) {
                throw new ParamException("参数缺失:" + param);
            }
        }
    }

    /**
     * 校验是否包含参数
     *
     * @param thisClass
     * @param data
     * @param property
     * @param <T>
     * @return
     */
    public static <T> boolean paramValid(Class<?> thisClass, T data, String property) {
        boolean hasParam = false;
        Class<?> superclass = thisClass.getSuperclass();
        Field field = null;
        try {
            field = thisClass.getDeclaredField(property);
            field.setAccessible(true);
            Object param = field.get(data);
            hasParam = (param != null);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            if (superclass != null) {
                return paramValid(superclass, data, property);
            } else {
                throw new ParamException("未找到校验参数:" + property + "\r\n");
            }
        } finally {
            if (field != null) {
                field.setAccessible(false);
            }
        }
        //第一级时返回
        return hasParam;
    }

    /**
     * 编号补0
     *
     * @param num
     * @param length
     * @return
     */
    @NotNull
    public static String addZero(Integer num, Integer length) {
        String numStr = String.valueOf(num);
        StringBuffer numBuffer = new StringBuffer();
        int numSub = length - numStr.length();
        for (int j = 0; j < numSub; j++) {
            numBuffer.append("0");
        }
        numBuffer.append(num);
        return numBuffer.toString();
    }

    /**
     * 数字类型初始化
     *
     * @param data
     * @param <T>
     * @return
     */
    public static <T> T initMathData(T data) {
        if (data == null) {
            return null;
        }
        Class<?> aClass = data.getClass();
        Field[] classDeclaredFields = aClass.getDeclaredFields();

        for (int i = 0; i < classDeclaredFields.length; i++) {
            Field field = classDeclaredFields[i];
            field.setAccessible(true);
            try {
                if (field.get(data) == null) {
                    if ("java.math.BigDecimal".equals(field.getType().getName())) {
                        field.set(data, BigDecimal.ZERO);
                    } else if ("java.lang.Integer".equals(field.getType().getName())) {
                        field.set(data, 0);
                    } else if ("java.lang.Long".equals(field.getType().getName())) {
                        field.set(data, 0L);
                    } else if ("java.lang.Double".equals(field.getType().getName())) {
                        field.set(data, 0d);
                    } else if ("java.lang.Float".equals(field.getType().getName())) {
                        field.set(data, 0f);
                    }
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
            field.setAccessible(false);
        }
        return data;
    }

    /**
     * 排除性强制初始化
     *
     * @param data
     * @param excludes 属性名
     * @param <T>
     * @return
     */
    public static <T> T initMathData(T data, List<String> excludes) {
        if (data == null) {
            return null;
        }
        Class<?> aClass = data.getClass();
        Field[] classDeclaredFields = aClass.getDeclaredFields();

        for (int i = 0; i < classDeclaredFields.length; i++) {
            Field field = classDeclaredFields[i];
            if (excludes.contains(field.getName())) {
                continue;
            }
            field.setAccessible(true);
            try {
                if ("java.math.BigDecimal".equals(field.getType().getName())) {
                    field.set(data, BigDecimal.ZERO);
                } else if ("java.lang.Integer".equals(field.getType().getName())) {
                    field.set(data, 0);
                } else if ("java.lang.Long".equals(field.getType().getName())) {
                    field.set(data, 0L);
                } else if ("java.lang.Double".equals(field.getType().getName())) {
                    field.set(data, 0d);
                } else if ("java.lang.Float".equals(field.getType().getName())) {
                    field.set(data, 0f);
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
            field.setAccessible(false);
        }
        return data;
    }

    /**
     * 类名转表名
     *
     * @return
     */
    public static String className2TableName(Class<?> clazz) {
        String name = clazz.getSimpleName();
        StringBuffer nameBuffer = new StringBuffer();
        for (int i = 0; i < name.length(); i++) {
            char c = name.charAt(i);
            if (Character.isUpperCase(c) && i != 0) {
                nameBuffer.append("_");
                nameBuffer.append(Character.toLowerCase(c));
            } else {
                nameBuffer.append(Character.toLowerCase(c));
            }
        }
        return nameBuffer.toString();
    }

    /**
     * 属性名转表名
     *
     * @param propertyName
     * @return
     */
    public static String propertyName2ColumnName(String propertyName) {
        String name = propertyName;
        StringBuffer nameBuffer = new StringBuffer();
        for (int i = 0; i < name.length(); i++) {
            char c = name.charAt(i);
            if (Character.isUpperCase(c) && i != 0) {
                nameBuffer.append("_");
                nameBuffer.append(Character.toLowerCase(c));
            } else {
                nameBuffer.append(Character.toLowerCase(c));
            }
        }
        return nameBuffer.toString();
    }


    /**
     * 必要参数是否缺失
     *
     * @param params
     * @return
     */
    public static Map<String, String> requisiteParam(String... params) {
        Map<String, String[]> paramMap = Kit.getRequest().getParameterMap();
        Map<String, String> resultMap = new HashMap<>();

        StringBuffer paramSb = new StringBuffer();

        for (String key : paramMap.keySet()) {
            String[] paramValArr = paramMap.get(key);
            if (paramValArr != null && paramValArr.length > 0) {
                //先判断参数值不为null和空字符
                if (StringUtils.isNotBlank(paramValArr[0])) {
                    //再判断参数是否存在
                    int index = ArrayUtil.indexOf(params, key);
                    if (index > -1) {
                        params = ArrayUtil.remove(params, index);
                    }
                    resultMap.put(key, ArrayUtil.join(paramValArr, ","));
                }
            }
        }

        //判断必传参数是否有值，无值时抛出异常
        if (params.length >= 1) {
            throw new ParamException(ArrayUtil.toString(params));
        }
        return resultMap;
    }

    /**
     * 表名转类名
     *
     * @param tableName
     * @return
     */
    @NotNull
    public static String columnName2PropertyName(@NotNull String tableName) {
        String[] split = tableName.split("_");
        StringBuffer buffer = new StringBuffer();
        for (int i = 0, len = split.length; i < len; i++) {
            String splitName = split[i];
            if (i != 0) {
                char c = splitName.charAt(0);
                String substring = splitName.substring(1, splitName.length());
                buffer.append(String.valueOf(c).toUpperCase() + substring);
            } else {
                buffer.append(splitName);
            }
        }
        return buffer.toString();
    }


    /**
     * 验证是否为JSON格式数组
     * <p>
     * 通过com.alibaba.fastjson.JSONObject.parseArray解析来判断，解析成功，是json格式；否则，不是json格式
     *
     * @param str
     * @return
     */
    public static boolean isJsonArray(String str) {
        boolean result = false;
        try {
            com.alibaba.fastjson.JSONObject.parseArray(str);
            result = true;
        } catch (Exception e) {
            result = false;
        }
        return result;
    }

    /**
     * 把map的key按ASCII编码升序排序
     *
     * @param map
     * @return
     */
    public static String mapKeyToAscii(Map map) {
        if (map == null || map.size() == 0) {
            return null;
        }
        List<Map.Entry> mapList = new ArrayList<Map.Entry>(map.entrySet());
        // 对所有传入参数按照字段名的 ASCII 码从小到大排序（字典序）
        Collections.sort(mapList, new Comparator<Map.Entry>() {
            @Override
            public int compare(Map.Entry o1, Map.Entry o2) {
                return (o1.getKey()).toString().compareTo(o2.getKey().toString());
            }
        });

        // 构造签名键值对的格式
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> item : mapList) {
            if (item.getKey() != null || item.getKey() != "") {
                String key = item.getKey();
                Object val = item.getValue();
                if (val.getClass().isArray()) {
                    val = ArrayUtil.join(val, ",");
                }
                if (val != null) {
                    if (sb.length() >= 1) {
                        sb.append("&");
                    }
                    sb.append(key + "=" + val);
                }
            }
        }
        return sb.toString();
    }

    // 得到32位UUID
    public static String get32UUID() {
        UUID uuid = UUID.randomUUID();
        return uuid.toString().replace("-", "").substring(0, 31);
    }

    // 得到16位UUID
    public static String get16UUID() {
        UUID uuid = UUID.randomUUID();
        return uuid.toString().replace("-", "").substring(0, 15);
    }

    // 得到MD5摘要串
    public static String getMD5Str(String s) {
        // 用作十六进制的数组.
        byte hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
                'a', 'b', 'c', 'd', 'e', 'f'};
        try {
            MessageDigest mdTemp = MessageDigest.getInstance("MD5"
                    .toUpperCase());// 使用MD5加密
            byte[] strTemp = s.getBytes();// 把传入的字符串转换成字节数组
            mdTemp.update(strTemp);//
            byte[] md = mdTemp.digest();
            int j = md.length;
            byte str[] = new byte[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(str);// 返回加密后的字符串.
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }


    /**
     * 十六进制转十进制
     *
     * @param hex
     * @return
     */
    public static long hexToLong(String hex) {
        if (StringUtil.isBlank(hex)) {
            return 0;
        }
        long result = Long.parseUnsignedLong(hex.replace("0x", "").replace("0X", ""), 16);
        log.debug("将16进制[" + hex + "]转10进制[" + result + "]");
        return result;
    }

    static final String[] HIGH_LETTER = {"A", "B", "C", "D", "E", "F"};
    static final int HIGH_LETTER_LEN = HIGH_LETTER.length;

    /**
     * 十六进制转十进制
     *
     * @param hex
     * @return
     */
    public static int hexToInt(String hex) {
        if (StringUtil.isBlank(hex)) {
            return 0;
        }
        hex = hex.toUpperCase().replace("0X", "");
        int number = 0;

        Map<String, Integer> map = new HashMap<>(16);
        for (int i = 0; i <= 9; i++) {
            map.put(i + "", i);
        }
        for (int j = 10; j < HIGH_LETTER_LEN + 10; j++) {
            map.put(HIGH_LETTER[j - 10], j);
        }
        String[] str = new String[hex.length()];
        for (int i = 0; i < str.length; i++) {
            str[i] = hex.substring(i, i + 1);
        }
        for (int i = 0; i < str.length; i++) {
            number += map.get(str[i]) * Math.pow(16, str.length - 1 - i);
        }
        return number;
    }

    /**
     * 对象转map
     *
     * @param obj
     * @return
     */
    @NotNull
    public static Map<String, Object> objectToObjMap(Object obj) {
        Map<String, Object> map = new HashMap<>(16);
        if (obj == null) {
            return map;
        }
        Class<?> clazz = obj.getClass();
        try {
            for (Field field : clazz.getDeclaredFields()) {
                field.setAccessible(true);
                String fieldName = field.getName();
                Object value = field.get(obj);
                if (value != null) {
                    map.put(fieldName, value);
                }
            }
        } catch (IllegalAccessException e) {
            log.warn("对象转map异常！{}", e.getMessage());
        }
        return map;
    }


    /**
     * 对象转map
     *
     * @param obj
     * @return
     */
    @NotNull
    public static Map<String, String> objectToStrMap(Object obj) {
        Map<String, String> map = new HashMap<>(16);
        if (obj == null) {
            return map;
        }
        Class<?> clazz = obj.getClass();
        try {
            for (Field field : clazz.getDeclaredFields()) {
                field.setAccessible(true);
                String fieldName = field.getName();
                Object object = field.get(obj);
                if (object != null) {
                    String value = String.valueOf(object);
                    if (StringUtils.isNotBlank(value)) {
                        map.put(fieldName, value);
                    }
                }
            }
        } catch (IllegalAccessException e) {
            log.warn("对象转map异常！{}", e.getMessage());
        }
        return map;
    }


    /**
     * 获取网络文件大小
     *
     * @param networkUrl
     * @return 单位为：KB
     */
    public static double getFileLength(String networkUrl) {
        double length = 0.0;
        URL url;
        HttpURLConnection urlcon = null;
        try {
            url = new URL(networkUrl);
            urlcon = (HttpURLConnection) url.openConnection();
            //根据响应获取文件大小
            length = urlcon.getContentLength() / 1024.0;
            length = BigDecimal.valueOf(length).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        } finally {
            if (urlcon != null) {
                urlcon.disconnect();
            }
        }
        return length;
    }


    /**
     * 把一个id1,id2,id3格式的字符串改成('id1','id2','id3')
     *
     * @param ids
     * @return
     */
    @NotNull
    public static String getWhereByIds(String ids) {
        if (StringUtils.isNotBlank(ids)) {
            return getWhereByIdArr(ids.split(",")).trim();
        }
        return "('')";
    }


    /**
     * 把一个id1,id2,id3格式的字符串改成('id1','id2','id3')
     *
     * @param idArr
     * @return
     */
    @NotNull
    public static String getWhereByIdArr(String[] idArr) {
        if (idArr != null && idArr.length >= 1) {
            StringBuffer whereSb = new StringBuffer();
            for (int i = 0, len = idArr.length; i < len; i++) {
                if (whereSb.length() >= 1) {
                    whereSb.append(",");
                }
                whereSb.append("'" + idArr[i] + "'");
            }
            return "(" + whereSb.toString().trim() + ")";
        }
        return "('')";
    }

    /**
     * (特殊字符替换)
     *
     * @param
     * @return String    返回类型
     */
    @NotNull
    public static String htmlReplace(String str) {
        str = str.replace("&ldquo;", "“");
        str = str.replace("&rdquo;", "”");
        str = str.replace("&nbsp;", " ");
        str = str.replace("&amp;", "&");
        str = str.replace("&#39;", "'");
        str = str.replace("&rsquo;", "’");
        str = str.replace("&mdash;", "—");
        str = str.replace("&ndash;", "–");
        return str;
    }

    /**
     * 组装like
     *
     * @param str
     * @return "'%"+str+"%'"
     */
    @Nullable
    public static String getLikeStr(String str) {
        if (StringUtil.isBlank(str)) {
            return null;
        }
        str = "'%" + str + "%'";
        return str;
    }


    /**
     * @description 解析sql中的表名称
     * @date 2023/12/15
     * @author cloud fly
     */
    public static String parseTableName(String sql) {
        String regex = "(?i)\\bINSERT INTO\\s+([\\w.]+)";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(sql);
        if (matcher.find()) {
            return matcher.group(1);
        }
        regex = "(?i)\\bUPDATE\\s+([\\w.]+)";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(sql);
        if (matcher.find()) {
            return matcher.group(1);
        }
        regex = "(?i)\\bDELETE FROM\\s+([\\w.]+)";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(sql);
        if (matcher.find()) {
            return matcher.group(1);
        }
        regex = "(?i)\\bFROM\\s+([\\w.]+)";
        pattern = Pattern.compile(regex);
        matcher = pattern.matcher(sql);
        if (matcher.find()) {
            return matcher.group(1);
        }
        return null;
    }

    /**
     * 获取 class中所有字段
     *
     * @param classes
     * @return
     */
    public static List<Field> getAllField(Class<?> classes) {
        List<Field> fieldList = new ArrayList<>();
        while (classes != Object.class) {
            fieldList.addAll(Arrays.stream(classes.getDeclaredFields()).collect(Collectors.toList()));
            //获取父类
            classes = classes.getSuperclass();
        }
        return fieldList;
    }

    /**
     * @param age 年龄
     * @return string 出生日期
     * @description 根据年龄与当前日期计算出生日期
     * @date 2023/12/20
     * @author cloud fly
     */
    public static String getBirthday(Integer age) {
        LocalDate today = LocalDate.now();
        //计算出生日期
        LocalDate birthDate = today.minusYears(age);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        return birthDate.format(formatter);

    }

    public static int getAgeByBirthday(Date birthday) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(birthday);
        int startYear = calendar.get(Calendar.YEAR);
        Calendar calendar2 = Calendar.getInstance();
        calendar2.setTime(new Date());
        int endYear = calendar2.get(Calendar.YEAR);
        int age = endYear - startYear;
        if (age <= 0) {
            age = 1;
        }
        return age;

    }

    public static void main(String[] args) throws Exception {
        /*String sql = "INSERT INTO tbl_i18n  ( id,created_on,updated_on,created_on_utc,updated_on_utc,created_by,updated_by,del_flag,language_id,language,obj_id,obj_table,status,content ) VALUES( fd6b9a6d93c54b0fb188fdb24111d1f3,Fri Dec 15 16:02:56 CST 2023,null,Fri Dec 15 08:02:56 CST 2023,null,devdev,null,0,c,b,d,e,1,a )";
        sql = "UPDATE tbl_i18n  SET updated_on = Fri Dec 15 16:16:04 CST 2023,updated_on_utc = Fri Dec 15 08:16:04 CST 2023,updated_by = devdev WHERE  id = fd6b9a6d93c54b0fb188fdb24111d1f3";
        sql = "DELETE FROM tbl_i18n WHERE id = ?";
        String s = Kit.parseTableName(sql);
        System.out.println("表名称=" +s);*/

        //Kit.getBirthday(5);

        //Kit.test();

//        Kit.formatGmtDate(new Date());
//        Kit.formatAddSecondGmtDate(new Date(),31536000);

      /*  long timestamp = System.currentTimeMillis() / 1000;
        System.out.println(timestamp);

        String s = Kit.formatAddSecondTimeStamp(new Date(), ContextConstants.DEFAULT_PATIENT_EXPIRES_TIME.intValue());
        System.out.println("加秒后的时间戳= " + s);*/
        //System.out.println("校验结果= " + Kit.validateInternationalEmail("2524536211@qq.com"));
        // System.out.println("校验结果= " + Kit.isValidPassword("2524536211qq.com"));
        /*String plainkey = "aa" + "." + "bb";
        String hashkey = Kit.computeSha256Hash(plainkey);
        System.out.println("result:= " + hashkey);*/
//        String s = Kit.formatGmtDate(new Date(), "yyyy/MM/dd HH:mm:ss");
//        String dateByTimeZone = Kit.getDateByTimeZone(new Date(), 1, "yyyy/MM/dd HH:mm:ss");
//        System.out.println("result:= " + s);
//        System.out.println("dateByTimeZone:= " + dateByTimeZone);
        /*Instant now = Instant.now();
        System.out.println("UTC 时间: " + now);
        // 将 Instant 转换为 Date
        Date date = Date.from(now);
        System.out.println("UTC 时间 (Date 类型): " + Kit.formatDateTime(date,"yyyy-MM-dd HH:mm:ss"));*/

        Long aLong = Kit.timestampAddDayTimeZone(System.currentTimeMillis(), 2, "+00:00");
        System.out.println("格式化时间=" + Kit.formatDateTime(new Date(aLong), "yyyy-MM-dd HH:mm:ss"));

    }

    public static String analysisPolicyNumberFileData(MultipartFile file) {
        List<NewsExcelDTO> stringList = EasyExcelUtil.readExcelCSV(file, NewsExcelDTO.class);
        if (stringList == null || stringList.isEmpty()) {
            return null;
        }
        // 将提取的getPolno属性用逗号连接起来
        return stringList.stream().map(NewsExcelDTO::getPolno).collect(Collectors.joining(","));
    }

    // 解析日期时间,解析失败返回null
    // @format 常用格式1.yyyy-MM-dd HH:mm:ss 2.yyyy-MM-dd
    public static Date parseDateTimeStr(String dateTimeStr, String format) {
        dateTimeStr = dateTimeStr.replace('.', '-');
        dateTimeStr = dateTimeStr.replace('/', '-');
        SimpleDateFormat sdf = new SimpleDateFormat();
        sdf.applyPattern(format);
        Date date = null;
        try {
            date = sdf.parse(dateTimeStr);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return date;
    }

    /**
     * 格式化日期时间字符串
     *
     * @param date    日期
     * @param @format 常用格式1.yyyy-MM-dd HH:mm:ss 2.yyyy-MM-dd
     */
    public static String formatDateTime(Date date, String format) {
        if (date != null) {
            SimpleDateFormat sdf = new SimpleDateFormat();
            sdf.applyPattern(format);
            return sdf.format(date);
        } else {
            return "";
        }
    }

    /**
     * @description 日期格式化为GMT日期字符串
     * @date 2024/1/17
     * @author cloud fly
     */
    public static String formatGmtDate(Date currentDate, String pattern) {
        try {
            // 创建日期格式化对象
            SimpleDateFormat dateFormat = new SimpleDateFormat(pattern, Locale.ENGLISH);
            dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));

            // 格式化日期为指定格式
            String formattedDate = dateFormat.format(currentDate);

            return formattedDate;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String formatGmtDate(Date currentDate) {
        try {
            // 创建日期格式化对象
            SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH);
            dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));

            // 格式化日期为指定格式
            String formattedDate = dateFormat.format(currentDate);

            return formattedDate;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    public static String formatAddSecondGmtDate(Date currentDate, int second) {
        try {
            // 创建 Calendar 对象，并设置为当前时间
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(currentDate);

            // 将 Calendar 的秒数加上 31536000
            calendar.add(Calendar.SECOND, second);

            // 获取加上指定秒数后的时间
            Date newDate = calendar.getTime();

            // 创建日期格式化对象
            SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH);
            dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));

            // 格式化日期为指定格式
            String formattedDate = dateFormat.format(newDate);

            return formattedDate;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    public static String formatAddSecondTimeStamp(Date currentDate, int second) {
        try {
            // 创建 Calendar 对象，并设置为当前时间
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(currentDate);

            // 将 Calendar 的秒数加上 31536000
            calendar.add(Calendar.SECOND, second);

            // 获取加上指定秒数后的时间
            Date newDate = calendar.getTime();
            return (newDate.getTime() / 1000) + "";

        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * @description 校验邮箱基本格式 匹配邮箱格式返回 true 否则返回 false
     * @date 2024/1/18
     * @author cloud fly
     */
    public static boolean validateInternationalEmail(String email) {
        // 正则表达式验证国际邮箱格式
        String regex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(email);
        return matcher.matches();
    }

    /**
     * @description 校验密码合法性
     * @date 2024/1/19
     * @author cloud fly
     */
    public static boolean isValidPassword(String password) {
        // 密码必须包含字母、数字和特殊字符，且长度在8到50之间
        String regex = "^(?=.*[a-zA-Z])(?=.*\\d)(?=.*[@#$%^&+=!]).{8,50}$";
        Pattern pattern = Pattern.compile(regex);
        return pattern.matcher(password).matches();
    }

    /**
     * @description 生成随机字符串
     * @date 2024/1/13
     * @author cloud fly
     */
    public static String generateRandomString(int length) {
        String characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random random = new Random();
        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < length; i++) {
            int index = random.nextInt(characters.length());
            char randomChar = characters.charAt(index);
            sb.append(randomChar);
        }

        return sb.toString();
    }

    /**
     * @description 计算SHA-256 哈希值
     * @date 2024/1/22
     * @author cloud fly
     */
    public static String computeSha256Hash(String key) {
        try {
            // 创建SHA-256摘要算法实例
            MessageDigest digest = MessageDigest.getInstance("SHA-256");

            // 将输入转换为字节数组
            byte[] encodedHash = digest.digest(key.getBytes(StandardCharsets.UTF_8));

            // 将字节数组转换为十六进制字符串
            StringBuilder hexString = new StringBuilder();
            for (byte b : encodedHash) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) {
                    hexString.append('0');
                }
                hexString.append(hex);
            }

            return hexString.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 复制对象中相同属性的值
     * @param source 源对象
     * @param target 目标对象
     */
    /**
     * 复制 Map 中相同键值对的属性值到指定对象中
     *
     * @param map    Map 对象
     * @param target 目标对象
     */
    public static void copyProperties(Map<String, Object> map, Object target) {
        // 获取目标对象的 Class 对象
        Class<?> targetClass = target.getClass();

        // 遍历 Map 中所有的键值对
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            // 获取键和值
            String key = entry.getKey();
            Object value = entry.getValue();

            // 查找目标对象是否有相同的属性
            try {
                Field targetField = targetClass.getDeclaredField(key);

                // 如果目标对象中有相同的属性，则将 Map 中该键对应的值赋给目标对象中对应的属性
                if (targetField.getType().isInstance(value)) {
                    targetField.setAccessible(true);
                    targetField.set(target, value);
                }
            } catch (NoSuchFieldException | IllegalAccessException e) {
                // 如果目标对象中没有相同的属性，则忽略该键值对
            }
        }
    }


    public static Long timestampAddDayTimeZone(long timestamp, int daysToAdd, String timeZone) {
//        long timestamp = 1643991600000L; // 13位时间戳
//        int daysToAdd = 5; // 要增加的天数
//        String timeZone = "Asia/Shanghai"; // 指定时区
        Instant instant = Instant.ofEpochMilli(timestamp);
        ZoneId zoneId = ZoneId.of(timeZone);
        ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(instant, zoneId);

        LocalDateTime localDateTime = zonedDateTime.toLocalDateTime();
        LocalDateTime newLocalDateTime = localDateTime.plusDays(daysToAdd);

        ZonedDateTime newZonedDateTime = newLocalDateTime.atZone(zoneId);
        Instant newInstant = newZonedDateTime.toInstant();
        long newTimestamp = newInstant.toEpochMilli();

        System.out.println("原始时间戳: " + timestamp);
        System.out.println("增加 " + daysToAdd + " 天后的时间戳: " + newTimestamp);
        return newTimestamp;
    }


       /**
        * @description 获取在线的BookingIds (websocket 通道正常在线)
        * @date     2024/3/4
        * @author   cloud fly
        */
    public static String getOnLineBookingIds() {
        String str = "";
        Set<String> keys = JedisUtil.keys("bookingId:*", CodeEnum.REDIS_HEARTBEAT.codeOf());
        if(keys!= null && !keys.isEmpty()) {
            str = String.join(",", keys);
        }
        if(StringUtils.isNotEmpty(str)) {
            str = Kit.getWhereByIds(str.replace("bookingId:",""));
        }
        return str;
    }
}
